// File Operations Tools Implementation

import * as fs from 'fs';
import * as path from 'path';
import {
    ToolHandler,
    ToolResult,
    ToolExecutionContext,
    ValidationResult
} from '../core/interfaces';

/**
 * 文件读取工具
 */
export class ReadFileHandler implements ToolHandler {
    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const { path: filePath, encoding = 'utf8' } = parameters;

        try {
            const absolutePath = this.resolveFilePath(filePath, context.workspaceRoot);
            const content = await fs.promises.readFile(absolutePath, encoding);

            return {
                success: true,
                data: {
                    content: content,
                    path: filePath,
                    size: content.length,
                    encoding: encoding
                }
            };
        } catch (error) {
            throw new Error(`Failed to read file: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (!parameters.path || typeof parameters.path !== 'string') {
            errors.push('path parameter is required and must be a string');
        }

        if (parameters.encoding && typeof parameters.encoding !== 'string') {
            errors.push('encoding parameter must be a string');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }

    private resolveFilePath(filePath: string, workspaceRoot?: string): string {
        if (path.isAbsolute(filePath)) {
            return filePath;
        }

        if (workspaceRoot) {
            return path.resolve(workspaceRoot, filePath);
        }

        return path.resolve(filePath);
    }
}

/**
 * 文件保存工具
 */
export class SaveFileHandler implements ToolHandler {
    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const { path: filePath, content, encoding = 'utf8', add_last_line_newline = true } = parameters;

        try {
            const absolutePath = this.resolveFilePath(filePath, context.workspaceRoot);

            // 确保目录存在
            const dir = path.dirname(absolutePath);
            await fs.promises.mkdir(dir, { recursive: true });

            // 处理内容
            let finalContent = content;
            if (add_last_line_newline && !finalContent.endsWith('\n')) {
                finalContent += '\n';
            }

            await fs.promises.writeFile(absolutePath, finalContent, encoding);

            return {
                success: true,
                data: {
                    path: filePath,
                    size: finalContent.length,
                    encoding: encoding
                }
            };
        } catch (error) {
            throw new Error(`Failed to save file: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (!parameters.path || typeof parameters.path !== 'string') {
            errors.push('path parameter is required and must be a string');
        }

        if (!parameters.content || typeof parameters.content !== 'string') {
            errors.push('content parameter is required and must be a string');
        }

        if (parameters.encoding && typeof parameters.encoding !== 'string') {
            errors.push('encoding parameter must be a string');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }

    private resolveFilePath(filePath: string, workspaceRoot?: string): string {
        if (path.isAbsolute(filePath)) {
            return filePath;
        }

        if (workspaceRoot) {
            return path.resolve(workspaceRoot, filePath);
        }

        return path.resolve(filePath);
    }
}

/**
 * 字符串替换编辑器工具
 */
export class StrReplaceEditorHandler implements ToolHandler {
    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const {
            path: filePath,
            old_str,
            new_str,
            old_str_start_line_number,
            old_str_end_line_number
        } = parameters;

        try {
            const absolutePath = this.resolveFilePath(filePath, context.workspaceRoot);

            // 读取文件内容
            const content = await fs.promises.readFile(absolutePath, 'utf8');
            const lines = content.split('\n');

            // 验证行号
            if (old_str_start_line_number < 1 || old_str_start_line_number > lines.length) {
                throw new Error(`Invalid start line number: ${old_str_start_line_number}`);
            }

            if (old_str_end_line_number < old_str_start_line_number || old_str_end_line_number > lines.length) {
                throw new Error(`Invalid end line number: ${old_str_end_line_number}`);
            }

            // 提取要替换的内容
            const startIndex = old_str_start_line_number - 1;
            const endIndex = old_str_end_line_number - 1;
            const targetLines = lines.slice(startIndex, endIndex + 1);
            const targetContent = targetLines.join('\n');

            // 验证内容匹配
            if (targetContent !== old_str) {
                throw new Error('Old string does not match the content at specified line range');
            }

            // 执行替换
            const newLines = new_str.split('\n');
            const updatedLines = [
                ...lines.slice(0, startIndex),
                ...newLines,
                ...lines.slice(endIndex + 1)
            ];

            const updatedContent = updatedLines.join('\n');

            // 写回文件
            await fs.promises.writeFile(absolutePath, updatedContent, 'utf8');

            return {
                success: true,
                data: {
                    path: filePath,
                    linesReplaced: endIndex - startIndex + 1,
                    newLines: newLines.length,
                    oldContent: old_str,
                    newContent: new_str
                }
            };
        } catch (error) {
            throw new Error(`Failed to replace string in file: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (!parameters.path || typeof parameters.path !== 'string') {
            errors.push('path parameter is required and must be a string');
        }

        if (!parameters.old_str || typeof parameters.old_str !== 'string') {
            errors.push('old_str parameter is required and must be a string');
        }

        if (parameters.new_str === undefined || typeof parameters.new_str !== 'string') {
            errors.push('new_str parameter is required and must be a string');
        }

        if (!parameters.old_str_start_line_number || typeof parameters.old_str_start_line_number !== 'number') {
            errors.push('old_str_start_line_number parameter is required and must be a number');
        }

        if (!parameters.old_str_end_line_number || typeof parameters.old_str_end_line_number !== 'number') {
            errors.push('old_str_end_line_number parameter is required and must be a number');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }

    private resolveFilePath(filePath: string, workspaceRoot?: string): string {
        if (path.isAbsolute(filePath)) {
            return filePath;
        }

        if (workspaceRoot) {
            return path.resolve(workspaceRoot, filePath);
        }

        return path.resolve(filePath);
    }
}
